package com.ymx.darling.session.setting;

import com.ymx.darling.bean.sql.BoundSql;
import com.ymx.darling.bean.sql.Statement;
import com.ymx.darling.executor.statement.StatementType;
import com.ymx.darling.util.ArrayUtil;

import java.sql.CallableStatement;
import java.sql.JDBCType;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;

/**
 * 存储存储过程信息
 * @author 爱Java的小于
 */
public class Callable {
    private final String sqlStatement;
    private final Map<Integer, Object> inParamMap = new HashMap<>();
    private final Map<Integer, Integer> outParamMap = new HashMap<>();
    private final Map<Integer, Object> resultParamMap = new HashMap<>();

    public static Callable call(String callName) {
        callName = String.format("{call %s}", callName);
        return new Callable(callName);
    }

    private Callable(String sqlStatement) {
        this.sqlStatement = sqlStatement;
    }

    public Callable addParam(int index, Object value) {
        inParamMap.put(index, value);
        return this;
    }

    public Callable addOutParam(int index, JDBCType jdbcType) {
        outParamMap.put(index, jdbcType.getVendorTypeNumber());
        return this;
    }

    public Callable addNOutParam(int index, Object value, JDBCType jdbcType) {
        this.addParam(index, value);
        return this.addOutParam(index, jdbcType);
    }

    public void addCallableSetting(Statement statement) {
        Object[] params = new Object[inParamMap.size()];
        this.inParamMap.forEach((index, param) -> params[index - 1] = param);
        statement.setCallable(this);
        statement.setBoundSql(new BoundSql(sqlStatement, ArrayUtil.asList(params)));
        statement.setStatementType(StatementType.CALLABLE);
    }

    public void registerOutputParameters(CallableStatement callableStatement) throws SQLException {
        for (Integer index : this.outParamMap.keySet()) {
            callableStatement.registerOutParameter(index, this.outParamMap.get(index));
        }
    }

    public void handleOutputParameters(CallableStatement callableStatement) throws SQLException {
        for (Integer index : this.outParamMap.keySet()) {
            Object result = callableStatement.getObject(index);
            this.resultParamMap.put(index, result);
        }
    }

    public <T> T getResultParam(int index) {
        return (T)this.resultParamMap.get(index);
    }
}
